@RestResource(urlMapping = '/WechatClientProfile/*')
// esempio di richiesta: /ProductProfile?SalesforceId=123&SapId=123&RolId=123 

global class LP_WechatClientProfileService {

  //wrapper object for GET Response
  public class GetResponseBean {
    Id SalesforceId;
    String RolId;
    String SapId;
    String Title;
    String FirstName;
    String LastName;
    String Address;
    String ZipCode;
    String City;
    String Province;
    String MobilePhone;
    String Nationality;
    String Country;
    String Email;
    String MarketingFlag;
    String ProfilingFlag;
        String ProfilingCrossGroupFlag;
    Date Birthday;
    String Gender;
    Datetime CreationDate;
    String AgeRange;
    String Status;
    String OpenId;
    String UnionId;
    String Source;
    String RegistrationStore;
    String WeChatStore;
    String WeChatSaleAssistantId;
    Boolean CNCBDTFlag;

    public GetResponseBean(Contact c) {
      this.SalesforceId = c.Id;
      this.RolId = c.RolId__c;
      this.SapId = c.SapId__c;
      this.Title = c.Salutation; // handleSalutationValue(c.Salutation);
      this.FirstName = c.FirstName;
      this.LastName = c.LastName;
      this.Address = c.MailingStreet;
      this.ZipCode = c.MailingPostalCode;
      this.City = c.MailingCity;
      this.Province = c.MailingState;
      this.MobilePhone = c.MobilePhone;
      this.Nationality = c.Nationality__r.Code__c;
      this.Country = c.MailingCountry;
      this.Email = c.Email;
      this.MarketingFlag = consentPickToBool(c.MarketingConsent__c);
            this.ProfilingCrossGroupFlag= consentPickToBool(c.ProfilingCrossGroup__c);
      this.ProfilingFlag = consentPickToBool(c.ProfilingConsent__c);
      this.Birthday = c.Birthdate;
      this.Gender = c.Gender__c;
      this.CreationDate = c.AcquisitionDate__c;
      this.AgeRange = c.AgeRange__c;
      this.Status = c.Status__c;
      this.OpenId = c.OpenId__c;
      this.UnionId = c.UnionId__c;
      this.Source = c.WeChatSource__c;
      this.RegistrationStore = c.RegistrationStore__r.TaxiShopCode__c;
      this.WeChatStore = c.WeChatStore__r.TaxiShopCode__c;
      this.WeChatSaleAssistantId = c.WeChatSaleAssistant__r.PersonId__c;
      this.CNCBDTFlag = c.CNCBDTFlag__c;
    }
  }

  public class PostSuccessResponseBean {
    Id id;
    String sapId;
    String RegistrationStore;
    String WeChatStore;
    Boolean success;
    List<String> errors;

    public PostSuccessResponseBean(Contact c, String rS, String wcS) {
      this.id = c.Id;
      this.sapId = c.SapId__c;
      this.RegistrationStore = rS;
      this.WeChatStore = wcS;
      this.success = true;
      this.errors = new List<String> ();
    }
  }


  //wrapper object for ImportCustomerBean
  public class SaveCustomerRequestBean {

    String Title;
    String Name; //FirstName
    String Surname; //LastName
    String AddressLine1; //Address
    String PostCode; //ZipCode
    String AddressLine2; //City
    String County; //Province  (is it supposed to be Province though? since on postman has the same input as Country "IT" which shouldnt be a valid province code)
    String TelPrefix; //Prefix
    String MobileNumber; //MobilePhone
    String Nationality;
    String Country;
    String EmailAddress; //Email
    Boolean MarketingConsent; //MarketingFlag (Should I make these Boolean MarketingConsent)
    Boolean ProfilePurposeConsent; //ProfilingFlag (Should I make these Boolean ProfilePurposeConsent)
        Boolean ProfilingCrossGroupConsent;
    String DateOfBirthday; //Birthday
    String Gender;
    String IssueDate; //CreationDate
    String Code;
    String StoreCode;
    String Version;
    Blob Signature; //We are supposed to have this on Bean right? just dont assign it any value?
    String targetSystem;
    String openId;
    String unionId;
    String sapId;
    String salesAssistantGlobalId;
    String PrivacyCN;
    Boolean readyForSale;

    public SaveCustomerRequestBean(String title, String firstname, String lastname, String address, String zip, String city, String province, String prefix, String mobile,
                     String nationality, String country, String email, String marketing, String profiling, String profilingcrossgroup, Datetime birthday, String gender, Datetime issueDt,
                     String code, String storecode, String version, Blob signature, String target, String openId, String unionId, String sap, String saId, Boolean readyForSale) {
    
      this(title, firstname, lastname, address, zip, city, province, prefix, mobile, nationality, country, email, marketing, profiling, profilingcrossgroup, birthday,
                     gender, issueDt, code, storecode, version, signature, target, openId, unionId, sap, saId,   null, readyForSale);

    }

    public SaveCustomerRequestBean(String title, String firstname, String lastname, String address, String zip, String city, String province, String prefix, String mobile,
                                   String nationality, String country, String email, String marketing, String profiling, String profilingcrossgroup, Datetime birthday, String gender, Datetime issueDt,
                     String code, String storecode, String version, Blob signature, String target, String openId, String unionId, String sap, String saId,
                     String PIPLConsent, Boolean readyForSale) {

      this.Title = title;
      this.Name = firstname;
      this.Surname = lastname;
      this.AddressLine1 = address;
      this.PostCode = zip;
      this.AddressLine2 = city;
      this.County = (province == null || province == '') ? province : handleESBCountryProvince(country, province).get('Province');
      this.TelPrefix = prefix;
      this.MobileNumber = mobile;
      this.Nationality = nationality;
      this.Country = (country == null || country == '') ? country : handleESBCountryProvince(country, province).get('Country');
      this.EmailAddress = email;
      this.MarketingConsent = (marketing == null) ? Boolean.valueOf('') : Boolean.valueOf(marketing);
      this.ProfilePurposeConsent = (profiling == null) ? Boolean.valueOf('') : Boolean.valueOf(profiling);
      this.DateOfBirthday = (birthday == null) ? '' : birthday.format('YYYY-MM-dd');
      this.Gender = gender;
      this.IssueDate = (issueDt == null) ? '' : issueDt.format('YYYY-MM-dd');
      this.Code = code;
      this.StoreCode = storecode;
      this.Version = version;
      this.Signature = signature;
      this.targetSystem = target;
      this.openId = openId;
      this.unionId = unionId;
      this.sapId = sap;
      this.salesAssistantGlobalId = saId;
      this.PrivacyCN = PIPLConsent;
            this.ProfilingCrossGroupConsent = (profilingcrossgroup == null) ? null : Boolean.valueOf(profilingcrossgroup);
      this.readyForSale = readyForSale;
      system.debug('#####');
      system.debug('ho ricevuto PIPLConsent ' + PIPLConsent);
      system.debug('sto mandando PrivacyCN ' + this.PrivacyCN);
    }
  }

  //wrapper object for ESB JSON Request Body
  public class ImportCustomerBean {
    SaveCustomerRequestBean SaveCustomerRequest;

    public ImportCustomerBean(SaveCustomerRequestBean esbRequest) {
      this.SaveCustomerRequest = esbRequest;
    }
  }

  //wrapper object for ImportCustomerBean
  public class SaveCustomerRequestBean2 {

    String Title;
    String FirstName; //FirstName
    String LastName; //LastName
    String Address; //Address
    String ZipCode; //ZipCode
    String City; //City
    String Province; //Province  (is it supposed to be Province though? since on postman has the same input as Country "IT" which shouldnt be a valid province code)
    String Prefix; //Prefix
    String MobilePhone; //MobilePhone
    String Nationality;
    String Country;
    String Email; //Email
    Boolean MarketingFlag; //MarketingFlag (Should I make these Boolean MarketingConsent)
    Boolean ProfilingFlag; //ProfilingFlag (Should I make these Boolean ProfilePurposeConsent)
        Boolean ProfilingCrossGroupFlag;
    String Birthday; //Birthday
    String Gender;
    String CreationDate; //CreationDate
    // String Code;
    String StoreCode;
    // String Version;
    // Blob Signature; //We are supposed to have this on Bean right? just dont assign it any value?
    // String targetSystem;
    String OpenId;
    String UnionId;
    String SapId;
    String SaleAssistantId;
    // String PrivacyCN;
    // Boolean readyForSale;
    Boolean CNCBDTFlag;
    String Source;

    public SaveCustomerRequestBean2(String title, String firstname, String lastname, String address, String zip, String city, String province, String prefix, String mobile,
                     String nationality, String country, String email, String marketing, String profiling, String profilingcrossgroup, Datetime birthday, String gender, Datetime issueDt,
                     String code, String storecode, String version, Blob signature, String target, String openId, String unionId, String sap, String saId, Boolean readyForSale) {
    
      this(title, firstname, lastname, address, zip, city, province, prefix, mobile, nationality, country, email, marketing, profiling, profilingcrossgroup, birthday,
                     gender, issueDt, code, storecode, version, signature, target, openId, unionId, sap, saId, null, readyForSale, null);

    }

    public SaveCustomerRequestBean2(String title, String firstname, String lastname, String address, String zip, String city, String province, String prefix, String mobile,
                                   String nationality, String country, String email, String marketing, String profiling, String profilingcrossgroup, Datetime birthday, String gender, Datetime issueDt,
                     String code, String storecode, String version, Blob signature, String target, String openId, String unionId, String sap, String saId,
                     String PIPLConsent, Boolean readyForSale, String strSource) {

      this.Title = title;
      this.FirstName = firstname;
      this.LastName = lastname;
      this.Address = address;
      this.ZipCode = zip;
      this.City = city;
      this.Province = (province == null || province == '') ? province : handleESBCountryProvince(country, province).get('Province');
      this.Prefix = prefix;
      this.MobilePhone = mobile;
      this.Nationality = nationality;
      this.Country = (country == null || country == '') ? country : handleESBCountryProvince(country, province).get('Country');
      this.Email = email;
      this.MarketingFlag = (marketing == null) ? false : Boolean.valueOf(marketing);
      this.ProfilingFlag = (profiling == null) ? false : Boolean.valueOf(profiling);
      this.Birthday = (birthday == null) ? '' : birthday.format('YYYY-MM-dd');
      this.Gender = gender;
      this.CreationDate = (issueDt == null) ? '' : issueDt.format('YYYY-MM-dd');
      // this.Code = code;
      this.StoreCode = storecode;
      // this.Version = version;
      // this.Signature = signature;
      // this.targetSystem = target;
      this.OpenId = openId;
      this.UnionId = unionId;
      this.SapId = sap;
      this.SaleAssistantId = saId;
      // this.PrivacyCN = PIPLConsent;
            this.ProfilingCrossGroupFlag = (profilingcrossgroup == null) ? false : Boolean.valueOf(profilingcrossgroup);
      // this.readyForSale = readyForSale;
      this.CNCBDTFlag = PIPLConsent != null ? Boolean.valueOf(PIPLConsent) : false;
      this.Source = strSource;
      system.debug('#####');
      system.debug('ho ricevuto PIPLConsent ' + PIPLConsent);
      // system.debug('sto mandando PrivacyCN ' + this.PrivacyCN);
    }
  }

  //wrapper object for ESB JSON Request Body
  public class ImportCustomerBean2 {
    SaveCustomerRequestBean2 SaveCustomerRequest;

    public ImportCustomerBean2(SaveCustomerRequestBean2 esbRequest) {
      this.SaveCustomerRequest = esbRequest;
    }
  }

  // class variables
  static List<String> countryWeChat = new List<String> { 'HK', 'AM', 'TW' }; //input received from WeChat as Province code
  static List<String> countrySF = new List<String> { 'HK', 'MO', 'TW' }; //Country Code__c on SF respective of WeChat input

  static List<String> mandatoryFields = new List<String> { 'Title', 'StoreCode', 'Source' }; // Mandatory Fields

  static String WeChatImageName = 'WeChatLogo'; // Image name

  static Map<String, Id> storesMap = prepareStoreMap();
  static Map<String, Id> saleAssistantMap = preparesaleAssistantMap();

  @HttpGet
  global static void GetWechatClientProfile() {
    RestRequest req = RestContext.request;
    RestResponse res = RestContext.response;
    res.addHeader('Content-Type', 'application/json');

    String req_SalesforceId = req.params.get('SalesforceId');
    String reqsapId = req.params.get('SapId');
    String req_RolId = req.params.get('RolId');

    JSONGenerator gen = JSON.createGenerator(true);
    Contact c;

    try {
      // REQUEST WITH SAP ID
      if (!String.isBlank(reqsapId)) {
        List<Contact> cList = [SELECT Id, RolId__c, SapId__c, Salutation, FirstName, LastName, MailingStreet, MailingPostalCode, MailingCity, MailingState, MobilePhone,
                               Nationality__r.Code__c, MailingCountry, Email, MarketingConsent__c, ProfilingConsent__c, Birthdate, Gender__c, AcquisitionDate__c,
                               AgeRange__c, Status__c, OpenId__c, UnionId__c, Source__c, FromWeChat__c, WeChatUniqueId__c, WeChatSource__c, CNCBDTFlag__c, 
                     RegistrationStore__c, RegistrationStore__r.TaxiShopCode__c, WeChatStore__c, WeChatStore__r.TaxiShopCode__c, PIPLConsent__c, 
                     WeChatSaleAssistant__c, WeChatSaleAssistant__r.Personid__c, RegistrationSaleAssistant__c, RegistrationSaleAssistant__r.Personid__c,ProfilingCrossGroup__c,

        (SELECT Street__c, PostalCode__c, City__c, Province__r.Code__c, Country__r.Code__c, Source__c, MainAddress__c, FromWeChat__c
         FROM Addresses__r
         WHERE Source__c = 'WeChat' OR FromWeChat__c = true),
        (SELECT PhonePrefix__c, Phone__c, Email__c, Source__c, MainChannel__c, Type__c, FromWeChat__c
         FROM ContactChannels__r
         WHERE Source__c = 'WeChat' OR FromWeChat__c = true)

                               FROM Contact
                               WHERE SapId__c = :reqsapId
                               LIMIT 1];

        if (cList.size() > 0 && cList != null) {

          if (cList[0].Addresses__r.size() > 0 && cList[0].Addresses__r != null) {

            List<Address__c> address = cList[0].Addresses__r;
            cList[0].MailingStreet = address[0].Street__c;
            cList[0].MailingPostalCode = address[0].PostalCode__c;
            cList[0].MailingCity = address[0].City__c;

            if (address[0].Country__r.Code__c != null) {

              if (countrySF.contains(address[0].Country__r.Code__c)) {
                cList[0].MailingCountry = 'CN';
                cList[0].MailingState = countryWeChat[countrySF.indexOf(address[0].Country__r.Code__c)];
              } else {
                cList[0].MailingState = (address[0].Province__r.Code__c != null) ? address[0].Province__r.Code__c : cList[0].MailingState;
                cList[0].MailingCountry = (address[0].Country__r.Code__c != null) ? address[0].Country__r.Code__c : cList[0].MailingCountry;
              }

            }

          }

          if (cList[0].ContactChannels__r.size() > 0 && cList[0].ContactChannels__r != null) {
            List<ContactChannel__c> channel = cList[0].ContactChannels__r;

            for (ContactChannel__c cc : channel) {
              switch on(cc.Type__c) {
                when 'EMAIL' {
                  cList[0].Email = cc.Email__c;
                }
                when 'MOB_PHONE' {
                  String phone = '';
                  if (cc.PhonePrefix__c != null) {
                    phone = cc.PhonePrefix__c + ' ';
                  }
                  cList[0].MobilePhone = phone + cc.Phone__c;
                }
                when else {
                  //noop
                }
              }
            }
          }

          GetResponseBean resBody = new GetResponseBean(cList[0]);

          gen.writeObject(resBody);
          string json_str = gen.getAsString();

          res.responseBody = Blob.valueOf(json_str);
          res.statusCode = 200;
        } else { // CONTACT NOT FOUND
          gen.writeStartObject();
          gen.writeStringField('ErrorDetails', 'Client Profile not found with Sap Id: ' + reqsapId);
          gen.writeEndObject();
          string json_str = gen.getAsString();

          res.responseBody = Blob.valueOf(json_str);
          res.statusCode = 404;
        }
        // REQUEST WITH ROL ID
      } else if (!String.isBlank(req_RolId)) {
        List<Contact> cList = [SELECT Id, RolId__c, SapId__c, Salutation, FirstName, LastName, MailingStreet, MailingPostalCode, MailingCity, MailingState, MobilePhone,
                               Nationality__r.Code__c, MailingCountry, Email, MarketingConsent__c, ProfilingConsent__c, Birthdate, Gender__c, AcquisitionDate__c,
                               AgeRange__c, Status__c, OpenId__c, UnionId__c, Source__c, FromWeChat__c, WeChatUniqueId__c, WeChatSource__c, CNCBDTFlag__c, 
                     RegistrationStore__c, RegistrationStore__r.TaxiShopCode__c, WeChatStore__c, WeChatStore__r.TaxiShopCode__c, PIPLConsent__c, 
                     WeChatSaleAssistant__c, WeChatSaleAssistant__r.Personid__c, RegistrationSaleAssistant__c, RegistrationSaleAssistant__r.Personid__c,ProfilingCrossGroup__c,

        (SELECT Street__c, PostalCode__c, City__c, Province__r.Code__c, Country__r.Code__c, Source__c, MainAddress__c, FromWeChat__c
         FROM Addresses__r
         WHERE Source__c = 'WeChat' OR FromWeChat__c = true),
        (SELECT PhonePrefix__c, Phone__c, Email__c, Source__c, MainChannel__c, Type__c, FromWeChat__c
         FROM ContactChannels__r
         WHERE Source__c = 'WeChat' OR FromWeChat__c = true)

                               FROM Contact
                               WHERE RolId__c = :req_RolId AND Canceled__c = false //MM: to add check only for active contacts, rol if won't be unique
                               LIMIT 1];

        if (cList.size() > 0 && cList != null) {

          if (cList[0].Addresses__r.size() > 0 && cList[0].Addresses__r != null) {

            List<Address__c> address = cList[0].Addresses__r;
            cList[0].MailingStreet = address[0].Street__c;
            cList[0].MailingPostalCode = address[0].PostalCode__c;
            cList[0].MailingCity = address[0].City__c;

            if (address[0].Country__r.Code__c != null) {

              if (countrySF.contains(address[0].Country__r.Code__c)) {
                cList[0].MailingCountry = 'CN';
                cList[0].MailingState = countryWeChat[countrySF.indexOf(address[0].Country__r.Code__c)];
              } else {
                cList[0].MailingState = (address[0].Province__r.Code__c != null) ? address[0].Province__r.Code__c : cList[0].MailingState;
                cList[0].MailingCountry = (address[0].Country__r.Code__c != null) ? address[0].Country__r.Code__c : cList[0].MailingCountry;
              }
            }

          }

          if (cList[0].ContactChannels__r.size() > 0 && cList[0].ContactChannels__r != null) {
            List<ContactChannel__c> channel = cList[0].ContactChannels__r;

            for (ContactChannel__c cc : channel) {
              switch on(cc.Type__c) {
                when 'EMAIL' {
                  cList[0].Email = cc.Email__c;
                }
                when 'MOB_PHONE' {
                  String phone = '';
                  if (cc.PhonePrefix__c != null) {
                    phone = cc.PhonePrefix__c + ' ';
                  }
                  cList[0].MobilePhone = phone + cc.Phone__c;
                }
                when else {
                  //noop
                }
              }
            }
          }

          GetResponseBean resBody = new GetResponseBean(cList[0]);

          gen.writeObject(resBody);
          string json_str = gen.getAsString();

          res.responseBody = Blob.valueOf(json_str);
          res.statusCode = 200;
        } else { // CONTACT NOT FOUND
          gen.writeStartObject();
          gen.writeStringField('ErrorDetails', 'Client Profile not found with ROL Id: ' + req_RolId);
          gen.writeEndObject();
          string json_str = gen.getAsString();

          res.responseBody = Blob.valueOf(json_str);
          res.statusCode = 404;
        }
        // REQUEST WITH SALESFORCE ID
      } else if (!String.isBlank(req_SalesforceId)) {
        List<Contact> cList = [SELECT Id, RolId__c, SapId__c, Salutation, FirstName, LastName, MailingStreet, MailingPostalCode, MailingCity, MailingState, MobilePhone,
                               Nationality__r.Code__c, MailingCountry, Email, MarketingConsent__c, ProfilingConsent__c, Birthdate, Gender__c, AcquisitionDate__c,
                               AgeRange__c, Status__c, OpenId__c, UnionId__c, Source__c, FromWeChat__c, WeChatUniqueId__c, WeChatSource__c, CNCBDTFlag__c, 
                     RegistrationStore__c, RegistrationStore__r.TaxiShopCode__c, WeChatStore__c, WeChatStore__r.TaxiShopCode__c, PIPLConsent__c, 
                     WeChatSaleAssistant__c, WeChatSaleAssistant__r.Personid__c, RegistrationSaleAssistant__c, RegistrationSaleAssistant__r.Personid__c,ProfilingCrossGroup__c,

        (SELECT Street__c, PostalCode__c, City__c, Province__r.Code__c, Country__r.Code__c, Source__c, MainAddress__c, FromWeChat__c
         FROM Addresses__r
         WHERE Source__c = 'WeChat' OR FromWeChat__c = true),
        (SELECT PhonePrefix__c, Phone__c, Email__c, Source__c, MainChannel__c, Type__c, FromWeChat__c
         FROM ContactChannels__r
         WHERE Source__c = 'WeChat' OR FromWeChat__c = true)

                               FROM Contact
                               WHERE Id = :req_SalesforceId
                               LIMIT 1];

        if (cList.size() > 0 && cList != null) {

          if (cList[0].Addresses__r.size() > 0 && cList[0].Addresses__r != null) {

            List<Address__c> address = cList[0].Addresses__r;
            cList[0].MailingStreet = address[0].Street__c;
            cList[0].MailingPostalCode = address[0].PostalCode__c;
            cList[0].MailingCity = address[0].City__c;

            if (address[0].Country__r.Code__c != null) {

              if (countrySF.contains(address[0].Country__r.Code__c)) {
                cList[0].MailingCountry = 'CN';
                cList[0].MailingState = countryWeChat[countrySF.indexOf(address[0].Country__r.Code__c)];
              } else {
                cList[0].MailingState = (address[0].Province__r.Code__c != null) ? address[0].Province__r.Code__c : cList[0].MailingState;
                cList[0].MailingCountry = (address[0].Country__r.Code__c != null) ? address[0].Country__r.Code__c : cList[0].MailingCountry;
              }
            }

          }

          if (cList[0].ContactChannels__r.size() > 0 && cList[0].ContactChannels__r != null) {
            List<ContactChannel__c> channel = cList[0].ContactChannels__r;

            for (ContactChannel__c cc : channel) {
              switch on(cc.Type__c) {
                when 'EMAIL' {
                  cList[0].Email = cc.Email__c;
                }
                when 'MOB_PHONE' {
                  String phone = '';
                  if (cc.PhonePrefix__c != null) {
                    phone = cc.PhonePrefix__c + ' ';
                  }
                  cList[0].MobilePhone = phone + cc.Phone__c;
                }
                when else {
                  //noop
                }
              }
            }
          }

          GetResponseBean resBody = new GetResponseBean(cList[0]);

          gen.writeObject(resBody);
          string json_str = gen.getAsString();

          res.responseBody = Blob.valueOf(json_str);
          res.statusCode = 200;
        } else { // CONTACT NOT FOUND
          gen.writeStartObject();
          gen.writeStringField('ErrorDetails', 'Client Profile not found with Salesforce Id: ' + req_SalesforceId);
          gen.writeEndObject();
          string json_str = gen.getAsString();

          res.responseBody = Blob.valueOf(json_str);
          res.statusCode = 404;
        }
        // REQUEST WITHOUT IDS
      } else {
        gen.writeStartObject();
        gen.writeStringField('ErrorDetails', 'Please insert at least one Id: SapId, SalesforceId, RolId.');
        gen.writeEndObject();
        string json_str = gen.getAsString();

        res.responseBody = Blob.valueOf(json_str);
        res.statusCode = 400;
      }
    } catch(Exception e) {
      gen.writeStartObject();
      gen.writeStringField('ErrorDetails', e.getMessage());
      gen.writeStringField('ErrorType', e.getTypeName());
      gen.writeStringField('ErrorStackTrace', e.getStackTraceString());
      gen.writeNumberField('LineError', e.getLineNumber());
      gen.writeEndObject();
      string json_str = gen.getAsString();

      res.responseBody = Blob.valueOf(json_str);
      res.statusCode = 500;
    }
    system.debug('Get ' + res.responseBody);
  }

  @HttpPost
  global static void PostWechatClientProfile(String Title, String FirstName, String LastName, String Address, String ZipCode, String City, String Province,
                                             String Prefix, String MobilePhone, String Nationality, String Country, String Email, String MarketingFlag, String ProfilingFlag,
                         Date Birthday, String Gender, Date CreationDate, String AgeRange, String OpenId, String UnionId, String Source, String StoreCode,
                         String SaleAssistantId, Boolean CNCBDTFlag, String ProfilingCrossGroupFlag) {

    JSONGenerator gen = JSON.createGenerator(true);
    RestResponse res = RestContext.response;
    res.addHeader('Content-Type', 'application/json');

    // MANDATORY FIELD CHECK
    List<String> mandatory = mandatoryFields;

    if (!String.isBlank(Title)) mandatory.remove(mandatory.indexOf('Title'));
    if (!String.isBlank(StoreCode)) mandatory.remove(mandatory.indexOf('StoreCode'));
    if (!String.isBlank(Source)) mandatory.remove(mandatory.indexOf('Source'));

    // CODES CHECK 
    Boolean existingStore = (!String.isBlank(StoreCode) && storesMap.get(StoreCode) != null) ? true : false;
    Boolean existingSaleAssistant = (String.isBlank(SaleAssistantId) || !String.isBlank(SaleAssistantId) && saleAssistantMap.get(SaleAssistantId) != null) ? true : false;    

    if (mandatory.size() == 0) {
      if (existingStore) {
        try {
          // handling of input values
          if (String.isBlank(Country) && !String.isBlank(Nationality)) {
            Country = Nationality;
          }
          Id SaleAssistant = (!String.isBlank(SaleAssistantId) && saleAssistantMap.get(SaleAssistantId) != null) ? saleAssistantMap.get(SaleAssistantId) : null;
          String CNCBDTFlagStr = String.valueof(CNCBDTFlag);

          Contact newContact = handleContact(Title, FirstName, LastName, Address, ZipCode, City, Province, Prefix, MobilePhone, Nationality, Country, Email,
                            MarketingFlag, ProfilingFlag, Birthday, Gender, CreationDate, AgeRange, OpenId, UnionId, Source,
                            storesMap.get(StoreCode), SaleAssistant, SaleAssistantId, null, CNCBDTFlagStr, ProfilingCrossGroupFlag);

          if (newContact != null) {
            Database.SaveResult contact_insertSaveResult = Database.insert(newContact, false);

            // CONTACT CREATED OK
            if (contact_insertSaveResult.isSuccess()) {
              // FUTURE METHOD TO UPDATE SAPAUTONUMBER CONTACT LOOKUP
              updateSapAutoNumberRecord(newContact.SapId__c, newContact.Id);
              // FUTURE METHOD TO INSERT ADDRESS/CONTACT_CHANNEL OBJECT RELATED TO CONTACT
              handleContactInfo(newContact.Id, Address, ZipCode, City, Province, Prefix, MobilePhone, Nationality, Country, Email, newContact.SapId__c, true);

              PostSuccessResponseBean resBody = new PostSuccessResponseBean(newContact, StoreCode, StoreCode);

              gen.writeObject(resBody);
              string json_str = gen.getAsString();

              res.responseBody = Blob.valueOf(json_str);
              res.statusCode = 201;

              /********* ESB INTEGRATION  **********
                 Parameters for  SaveCustomerRequestBean (String title, String firstname, String lastname, String address, String zip, String city, String province,String prefix,String mobile, 
                String nationality, String country, String email, String marketing, String profiling,Date birthday, String gender, Date creationDt, 
                String code, String storecode, String version, String signature, String target, String openId, String unionId, String sap)  ****/

              // SEND TO HYBRIS
              JSONGenerator genESB_H = JSON.createGenerator(true);

              String titleHybris = handleHybrisTitle(Title);

              // 2021-05-12 old request with D1M data
              /*SaveCustomerRequestBean customerRequest_H = new SaveCustomerRequestBean(titleHybris, FirstName, LastName, Address, ZipCode, City, Province, Prefix, MobilePhone,
                                                  Nationality, Country, Email, MarketingFlag, ProfilingFlag, Birthday, Gender, null,
                                                  newContact.SapId__c, StoreCode, '1', null, 'HYBRIS', OpenId, UnionId, newContact.SapId__c);*/
              // 2021-05-12 new request with SF data - Nationality resta così in quanto non è possibile recuperare il codice in modo agevole
              /*SaveCustomerRequestBean customerRequest_H = new SaveCustomerRequestBean(titleHybris, newContact.FirstName, newContact.LastName, newContact.MailingStreet, newContact.MailingPostalCode,
                                                  newContact.MailingCity, newContact.MailingState, newContact.WeChatPhonePrefix__c, newContact.WeChatPhone__c,
                                                  Nationality, newContact.MailingCountry, newContact.Email, consentPickToBool(newContact.MarketingConsent__c),
                                                  consentPickToBool(newContact.ProfilingConsent__c), newContact.Birthdate, newContact.Gender__c, null,
                                                  newContact.SapId__c, StoreCode, '1', null, 'HYBRIS', newContact.OpenId__c, newContact.UnionId__c, newContact.SapId__c);*/
              // 2021-07-28 update with Sale Assistant Id
              /* SaveCustomerRequestBean customerRequest_H = new SaveCustomerRequestBean(titleHybris, newContact.FirstName, newContact.LastName, newContact.MailingStreet, newContact.MailingPostalCode,
                                                  newContact.MailingCity, newContact.MailingState, newContact.WeChatPhonePrefix__c, newContact.WeChatPhone__c,
                                                  Nationality, newContact.MailingCountry, newContact.Email, consentPickToBool(newContact.MarketingConsent__c),
                                                  consentPickToBool(newContact.ProfilingConsent__c), newContact.Birthdate, newContact.Gender__c, null,
                                                  newContact.SapId__c, StoreCode, '4', null, 'HYBRIS', newContact.OpenId__c, newContact.UnionId__c, newContact.SapId__c,
                                                  newContact.WeChatSaleAssistantId__c, null);   */  
              //   2022-06-22 update with Ready fo Sale
              //   
              /*veCustomerRequestBean customerRequest_H = new SaveCustomerRequestBean(titleHybris, newContact.FirstName, newContact.LastName, newContact.MailingStreet, newContact.MailingPostalCode,
                                                  newContact.MailingCity, newContact.MailingState, newContact.WeChatPhonePrefix__c, newContact.WeChatPhone__c,
                                                  Nationality, newContact.MailingCountry, newContact.Email, consentPickToBool(newContact.MarketingConsent__c),
                                                  consentPickToBool(newContact.ProfilingConsent__c), consentPickToBool(newContact.ProfilingCrossGroup__c), newContact.Birthdate, newContact.Gender__c, null,
                                                  newContact.SapId__c, StoreCode, '4', null, 'HYBRIS', newContact.OpenId__c, newContact.UnionId__c, newContact.SapId__c,
                                                  newContact.WeChatSaleAssistantId__c, null, true);  
              ImportCustomerBean ESBCustomer_H = new ImportCustomerBean(customerRequest_H);
              genESB_H.writeObject(ESBCustomer_H);

              String json_esb_H = genESB_H.getAsString();
              handleESBIntegration(json_esb_H);
              */

              // SEND TO BEANSTORE        
              JSONGenerator genESB_B = JSON.createGenerator(true);

              List<ContentVersion> ContentVersions = [SELECT Id, VersionData FROM ContentVersion WHERE Title = :WeChatImageName ORDER BY VersionNumber DESC LIMIT 1];
              Blob base64WeChat = ContentVersions[0].VersionData;
              // 2021-05-12 old request with D1M data
              /*SaveCustomerRequestBean customerRequest_B = new SaveCustomerRequestBean(Title, FirstName, LastName, Address, ZipCode, City, Province, Prefix, MobilePhone,
                                                  Nationality, Country, Email, MarketingFlag, ProfilingFlag, Birthday, Gender, null,
                                                  newContact.SapId__c, StoreCode, '1', base64WeChat, 'BEANSTORE', OpenId, UnionId, newContact.SapId__c);*/
              // 2021-05-12 new request with SF data - Nationality resta così in quanto non è possibile recuperare il codice in modo agevole
              /*SaveCustomerRequestBean customerRequest_B = new SaveCustomerRequestBean(newContact.Salutation, newContact.FirstName, newContact.LastName, newContact.MailingStreet, newContact.MailingPostalCode,
                                                  newContact.MailingCity, newContact.MailingState, newContact.WeChatPhonePrefix__c, newContact.WeChatPhone__c,
                                                  Nationality, newContact.MailingCountry, newContact.Email, consentPickToBool(newContact.MarketingConsent__c),
                                                  consentPickToBool(newContact.ProfilingConsent__c), newContact.Birthdate, newContact.Gender__c, null,
                                                  newContact.SapId__c, StoreCode, '1', base64WeChat, 'BEANSTORE', newContact.OpenId__c, newContact.UnionId__c, newContact.SapId__c);*/
              // 2021-07-28 update with Sale Assistant Id
              /*SaveCustomerRequestBean customerRequest_B = new SaveCustomerRequestBean(newContact.Salutation, newContact.FirstName, newContact.LastName, newContact.MailingStreet, newContact.MailingPostalCode,
                                                  newContact.MailingCity, newContact.MailingState, newContact.WeChatPhonePrefix__c, newContact.WeChatPhone__c,
                                                  Nationality, newContact.MailingCountry, newContact.Email, consentPickToBool(newContact.MarketingConsent__c),
                                                  consentPickToBool(newContact.ProfilingConsent__c), newContact.Birthdate, newContact.Gender__c, null,
                                                  newContact.SapId__c, StoreCode, '4', base64WeChat, 'BEANSTORE', newContact.OpenId__c, newContact.UnionId__c, newContact.SapId__c,
                                                  newContact.WeChatSaleAssistantId__c);          */
              // 2021-10-25 update with PIPLConsent to BeanStore
              /* SaveCustomerRequestBean customerRequest_B = new SaveCustomerRequestBean(newContact.Salutation, newContact.FirstName, newContact.LastName, newContact.MailingStreet, newContact.MailingPostalCode,
                                                  newContact.MailingCity, newContact.MailingState, newContact.WeChatPhonePrefix__c, newContact.WeChatPhone__c,
                                                  Nationality, newContact.MailingCountry, newContact.Email, consentPickToBool(newContact.MarketingConsent__c),
                                                  consentPickToBool(newContact.ProfilingConsent__c), newContact.Birthdate, newContact.Gender__c, null,
                                                  newContact.SapId__c, StoreCode, '6', base64WeChat, 'BEANSTORE', newContact.OpenId__c, newContact.UnionId__c, newContact.SapId__c,
                                                  newContact.WeChatSaleAssistantId__c, consentPickToBool(newContact.PIPLConsent__c)); */
                                                  
              //   2022-06-22 update with Ready fo Sale                    
              SaveCustomerRequestBean2 customerRequest_B = new SaveCustomerRequestBean2(newContact.Salutation, newContact.FirstName, newContact.LastName, newContact.MailingStreet, newContact.MailingPostalCode,
                                                  newContact.MailingCity, newContact.MailingState, newContact.WeChatPhonePrefix__c, newContact.WeChatPhone__c,
                                                  Nationality, newContact.MailingCountry, newContact.Email, consentPickToBool(newContact.MarketingConsent__c),
                                                  consentPickToBool(newContact.ProfilingConsent__c), consentPickToBool(newContact.ProfilingCrossGroup__c), newContact.Birthdate, newContact.Gender__c, newContact.AcquisitionDate__c,
                                                  newContact.SapId__c, StoreCode, '8', base64WeChat, 'BEANSTORE', newContact.OpenId__c, newContact.UnionId__c, newContact.SapId__c,
                                                  newContact.WeChatSaleAssistantId__c, consentPickToBool(newContact.PIPLConsent__c), true, newContact.WeChatSource__c);  

              ImportCustomerBean2 ESBCustomer_B = new ImportCustomerBean2(customerRequest_B);
              // genESB_B.writeObject(ESBCustomer_B);
              // 24.7.29: Synchronize the contact to Beanstore and use Mulesoft as the middleware.
              genESB_B.writeObject(customerRequest_B);

              String json_esb_B = genESB_B.getAsString();
              handleESBIntegration(json_esb_B);

            } else { // CONTACT CREATED ERROR
              gen.writeObject(contact_insertSaveResult);
              string json_str = gen.getAsString();

              res.responseBody = Blob.valueOf(json_str);
              res.statusCode = 500;
            }
          }
        } catch(Exception e) {
          gen.writeStartObject();
          gen.writeStringField('ErrorDetails', e.getMessage());
          gen.writeStringField('ErrorType', e.getTypeName());
          gen.writeStringField('ErrorStackTrace', e.getStackTraceString());
          gen.writeNumberField('LineError', e.getLineNumber());
          gen.writeEndObject();
          string json_str = gen.getAsString();

          res.responseBody = Blob.valueOf(json_str);
          res.statusCode = 500;
        }
      } else {
        gen.writeStartObject();
        gen.writeStringField('ErrorDetails', 'Unknown StoreCode');
        gen.writeStringField('ErrorType', 'INVALID_STORE');

        gen.writeEndObject();
        string json_str = gen.getAsString();

        res.responseBody = Blob.valueOf(json_str);
        res.statusCode = 400;
      }
    } else {
      gen.writeStartObject();
      gen.writeStringField('ErrorDetails', 'Mandatory field(s) missing');
      gen.writeStringField('ErrorType', 'MANDATORY_FIELDS');
      gen.writeFieldName('ErrorFields');
      gen.writeStartArray();
      for (String s : mandatory) {
        gen.writeString(s);
      }
      gen.writeEndArray();

      gen.writeEndObject();
      string json_str = gen.getAsString();

      res.responseBody = Blob.valueOf(json_str);
      res.statusCode = 500;
    }
  }

  @HttpPatch
  global static void PatchWechatClientProfile(String Title, String FirstName, String LastName, String Address, String ZipCode, String City, String Province,
                                              String Prefix, String MobilePhone, String Nationality, String Country, String Email, String MarketingFlag, String ProfilingFlag,
                        Date Birthday, String Gender, Date CreationDate, String AgeRange, String OpenId, String UnionId, String Source, String StoreCode,
                        String SaleAssistantId, Boolean CNCBDTFlag, String ProfilingCrossGroupFlag) {

    JSONGenerator gen = JSON.createGenerator(true);
    RestResponse res = RestContext.response;
    RestRequest req = RestContext.request;
    res.addHeader('Content-Type', 'application/json');
    String requestedSapId = req.requestURI.substring(req.requestURI.lastIndexOf('/') + 1);

    // MANDATORY FIELD CHECK
    List<String> mandatory = mandatoryFields;

    if (!String.isBlank(Title)) mandatory.remove(mandatory.indexOf('Title'));
    if (!String.isBlank(StoreCode)) mandatory.remove(mandatory.indexOf('StoreCode'));
    if (!String.isBlank(Source)) mandatory.remove(mandatory.indexOf('Source'));

    // CODES CHECK 
    Boolean existingStore = (!String.isBlank(StoreCode) && storesMap.get(StoreCode) != null) ? true : false;
    Boolean existingSaleAssistant = (String.isBlank(SaleAssistantId) || !String.isBlank(SaleAssistantId) && saleAssistantMap.get(SaleAssistantId) != null) ? true : false;    

    if (mandatory.size() == 0) {
      if (existingStore) {
        try {
          // handling of input values            
          if (String.isBlank(Country) && !String.isBlank(Nationality)) {
            Country = Nationality;
          }
          Id SaleAssistant = (!String.isBlank(SaleAssistantId) && saleAssistantMap.get(SaleAssistantId) != null) ? saleAssistantMap.get(SaleAssistantId) : null;
          String CNCBDTFlagStr = String.valueof(CNCBDTFlag);

          Contact updatedContact = handleContact(Title, FirstName, LastName, Address, ZipCode, City, Province, Prefix, MobilePhone, Nationality, Country, Email,
                              MarketingFlag, ProfilingFlag, Birthday, Gender, CreationDate, AgeRange, OpenId, UnionId, Source,
                              storesMap.get(StoreCode), SaleAssistant, SaleAssistantId, requestedSapId, CNCBDTFlagStr, ProfilingCrossGroupFlag);

          if (updatedContact != null) {
            Database.SaveResult contact_updateSaveResult = Database.update(updatedContact, false);

            // CONTACT UPDATED OK
            if (contact_updateSaveResult.isSuccess()) {
              // INSERT OR UPDATE CONTACTS RELATED OBJECTS ADDRESS/CONTACT_CHANNEL DEPENDING ON PARAMETERS ADDED  
              handleContactInfo(updatedContact.Id, Address, ZipCode, City, Province, Prefix, MobilePhone, Nationality, Country, Email, requestedSapId, false);

              PostSuccessResponseBean resBody = new PostSuccessResponseBean(updatedContact, updatedContact.RegistrationStore__r.TaxiShopCode__c, StoreCode);

              gen.writeObject(resBody);
              string json_str = gen.getAsString();

              res.responseBody = Blob.valueOf(json_str);
              res.statusCode = 200;

              /********* ESB INTEGRATION  **********
                 Parameters for  SaveCustomerRequestBean (String title, String firstname, String lastname, String address, String zip, String city, String province,String prefix,String mobile, 
                String nationality, String country, String email, String marketing, String profiling,Date birthday, String gender, Date creationDt, 
                String code, String storecode, String version, String signature, String target, String openId, String unionId, String sap)  ****/

              // SEND TO HYBRIS
              JSONGenerator genESB_H = JSON.createGenerator(true);

              String titleHybris = handleHybrisTitle(Title);

              // if title is deduced, send to the esb the existing one, otherwise send the deduced one
              // 2021-05-12 old request with D1M data
              /*SaveCustomerRequestBean customerRequest_H = new SaveCustomerRequestBean(titleHybris, FirstName, LastName, Address, ZipCode, City, Province, Prefix, MobilePhone,
                                                  Nationality, Country, Email, MarketingFlag, ProfilingFlag, Birthday, Gender, null,
                                                  requestedSapId, StoreCode, '1', null, 'HYBRIS', OpenId, UnionId, requestedSapId);*/
              // 2021-05-12 new request with SF data - Nationality resta così in quanto non è possibile recuperare il codice in modo agevole
              /*SaveCustomerRequestBean customerRequest_H = new SaveCustomerRequestBean(titleHybris, updatedContact.FirstName, updatedContact.LastName, updatedContact.MailingStreet, updatedContact.MailingPostalCode,
                                                  updatedContact.MailingCity, updatedContact.MailingState, updatedContact.WeChatPhonePrefix__c, updatedContact.WeChatPhone__c,
                                                  Nationality, updatedContact.MailingCountry, updatedContact.Email, consentPickToBool(updatedContact.MarketingConsent__c),
                                                  consentPickToBool(updatedContact.ProfilingConsent__c), updatedContact.Birthdate, updatedContact.Gender__c, null,
                                                  updatedContact.SapId__c, StoreCode, '1', null, 'HYBRIS', updatedContact.OpenId__c, updatedContact.UnionId__c, updatedContact.SapId__c);*/
              // 2021-07-28 new request with Sale Assistant Id
              /* SaveCustomerRequestBean customerRequest_H = new SaveCustomerRequestBean(titleHybris, updatedContact.FirstName, updatedContact.LastName, updatedContact.MailingStreet, updatedContact.MailingPostalCode,
                                                  updatedContact.MailingCity, updatedContact.MailingState, updatedContact.WeChatPhonePrefix__c, updatedContact.WeChatPhone__c,
                                                  Nationality, updatedContact.MailingCountry, updatedContact.Email, consentPickToBool(updatedContact.MarketingConsent__c),
                                                  consentPickToBool(updatedContact.ProfilingConsent__c), updatedContact.Birthdate, updatedContact.Gender__c, null,
                                                  updatedContact.SapId__c, StoreCode, '4', null, 'HYBRIS', updatedContact.OpenId__c, updatedContact.UnionId__c, updatedContact.SapId__c,
                                                  updatedContact.WeChatSaleAssistantId__c, null); */
              //   2022-06-22 update with Ready fo Sale                      
              /*SaveCustomerRequestBean customerRequest_H = new SaveCustomerRequestBean(titleHybris, updatedContact.FirstName, updatedContact.LastName, updatedContact.MailingStreet, updatedContact.MailingPostalCode,
                                                  updatedContact.MailingCity, updatedContact.MailingState, updatedContact.WeChatPhonePrefix__c, updatedContact.WeChatPhone__c,
                                                  Nationality, updatedContact.MailingCountry, updatedContact.Email, consentPickToBool(updatedContact.MarketingConsent__c),
                                                  consentPickToBool(updatedContact.ProfilingConsent__c), consentPickToBool(updatedContact.ProfilingCrossGroup__c), updatedContact.Birthdate, updatedContact.Gender__c, null,
                                                  updatedContact.SapId__c, StoreCode, '4', null, 'HYBRIS', updatedContact.OpenId__c, updatedContact.UnionId__c, updatedContact.SapId__c,
                                                  updatedContact.WeChatSaleAssistantId__c/*, null, true);
              ImportCustomerBean ESBCustomer_H = new ImportCustomerBean(customerRequest_H);
              genESB_H.writeObject(ESBCustomer_H);

              String json_esb_H = genESB_H.getAsString();
              handleESBIntegration(json_esb_H);
              */
              // SEND TO BEANSTORE
              JSONGenerator genESB_B = JSON.createGenerator(true);

              List<ContentVersion> ContentVersions = [SELECT Id, VersionData FROM ContentVersion WHERE Title = :WeChatImageName ORDER BY VersionNumber DESC LIMIT 1];
              Blob base64WeChat = ContentVersions[0].VersionData;
              // if title is deduced, send to the esb the existing one, otherwise send the deduced one
              // 2021-05-12 old request with D1M data
              /*SaveCustomerRequestBean customerRequest_B = new SaveCustomerRequestBean(Title, FirstName, LastName, Address, ZipCode, City, Province, Prefix, MobilePhone,
                                                  Nationality, Country, Email, MarketingFlag, ProfilingFlag, Birthday, Gender, null,
                                                  requestedSapId, updatedContact.RegistrationStore__r.TaxiShopCode__c, '1', base64WeChat, 'BEANSTORE', OpenId, UnionId, requestedSapId);*/
              // 2021-05-12 new request with SF data - Nationality resta così in quanto non è possibile recuperare il codice in modo agevole
              /*SaveCustomerRequestBean customerRequest_B = new SaveCustomerRequestBean(updatedContact.Salutation, updatedContact.FirstName, updatedContact.LastName, updatedContact.MailingStreet, updatedContact.MailingPostalCode,
                                                  updatedContact.MailingCity, updatedContact.MailingState, updatedContact.WeChatPhonePrefix__c, updatedContact.WeChatPhone__c,
                                                  Nationality, updatedContact.MailingCountry, updatedContact.Email, consentPickToBool(updatedContact.MarketingConsent__c),
                                                  consentPickToBool(updatedContact.ProfilingConsent__c), updatedContact.Birthdate, updatedContact.Gender__c, null,
                                                  updatedContact.SapId__c, StoreCode, '1', base64WeChat, 'BEANSTORE', updatedContact.OpenId__c, updatedContact.UnionId__c, updatedContact.SapId__c);*/
              // 2021-07-28 new request with Sale Assistant Id
              /*SaveCustomerRequestBean customerRequest_B = new SaveCustomerRequestBean(updatedContact.Salutation, updatedContact.FirstName, updatedContact.LastName, updatedContact.MailingStreet, updatedContact.MailingPostalCode,
                                                  updatedContact.MailingCity, updatedContact.MailingState, updatedContact.WeChatPhonePrefix__c, updatedContact.WeChatPhone__c,
                                                  Nationality, updatedContact.MailingCountry, updatedContact.Email, consentPickToBool(updatedContact.MarketingConsent__c),
                                                  consentPickToBool(updatedContact.ProfilingConsent__c), updatedContact.Birthdate, updatedContact.Gender__c, null,
                                                  updatedContact.SapId__c, StoreCode, '4', base64WeChat, 'BEANSTORE', updatedContact.OpenId__c, updatedContact.UnionId__c, updatedContact.SapId__c,
                                                  updatedContact.WeChatSaleAssistantId__c);*/
              // 2021-10-25 update with PIPLConsent to BeanStore
              /* SaveCustomerRequestBean customerRequest_B = new SaveCustomerRequestBean(updatedContact.Salutation, updatedContact.FirstName, updatedContact.LastName, updatedContact.MailingStreet, updatedContact.MailingPostalCode,
                                                  updatedContact.MailingCity, updatedContact.MailingState, updatedContact.WeChatPhonePrefix__c, updatedContact.WeChatPhone__c,
                                                  Nationality, updatedContact.MailingCountry, updatedContact.Email, consentPickToBool(updatedContact.MarketingConsent__c),
                                                  consentPickToBool(updatedContact.ProfilingConsent__c), updatedContact.Birthdate, updatedContact.Gender__c, null,
                                                  updatedContact.SapId__c, StoreCode, '6', base64WeChat, 'BEANSTORE', updatedContact.OpenId__c, updatedContact.UnionId__c, updatedContact.SapId__c,
                                                  updatedContact.WeChatSaleAssistantId__c, consentPickToBool(updatedContact.PIPLConsent__c)); */

              SaveCustomerRequestBean2 customerRequest_B = new SaveCustomerRequestBean2(updatedContact.Salutation, updatedContact.FirstName, updatedContact.LastName, updatedContact.MailingStreet, updatedContact.MailingPostalCode,
                                                  updatedContact.MailingCity, updatedContact.MailingState, updatedContact.WeChatPhonePrefix__c, updatedContact.WeChatPhone__c,
                                                  Nationality, updatedContact.MailingCountry, updatedContact.Email, consentPickToBool(updatedContact.MarketingConsent__c),
                                                  consentPickToBool(updatedContact.ProfilingConsent__c), consentPickToBool(updatedContact.ProfilingCrossGroup__c), updatedContact.Birthdate, updatedContact.Gender__c, updatedContact.AcquisitionDate__c,
                                                  updatedContact.SapId__c, StoreCode, '8', base64WeChat, 'BEANSTORE', updatedContact.OpenId__c, updatedContact.UnionId__c, updatedContact.SapId__c,
                                                  updatedContact.WeChatSaleAssistantId__c, consentPickToBool(updatedContact.PIPLConsent__c), true, updatedContact.WeChatSource__c);
              ImportCustomerBean2 ESBCustomer_B = new ImportCustomerBean2(customerRequest_B);
              // genESB_B.writeObject(ESBCustomer_B);
              // 24.7.29: Synchronize the contact to Beanstore and use Mulesoft as the middleware.
              genESB_B.writeObject(customerRequest_B);

              String json_esb_B = genESB_B.getAsString();
              handleESBIntegration(json_esb_B);

            } else { // CONTACT UPDATED ERROR
              gen.writeObject(contact_updateSaveResult);
              string json_str = gen.getAsString();

              res.responseBody = Blob.valueOf(json_str);
              res.statusCode = 500;
            }
          }
        }
        catch(Exception e) {
                    System.debug(e.getMessage() + ' ' +  e.getLineNumber());
          gen.writeStartObject();
          gen.writeStringField('ErrorDetails', e.getMessage());
          gen.writeStringField('ErrorType', e.getTypeName());
          gen.writeStringField('ErrorStackTrace', e.getStackTraceString());
          gen.writeNumberField('LineError', e.getLineNumber());
          gen.writeEndObject();
          string json_str = gen.getAsString();

          res.responseBody = Blob.valueOf(json_str);
          res.statusCode = 500;
        }
      } else {
        gen.writeStartObject();
        gen.writeStringField('ErrorDetails', 'Unknown StoreCode');
        gen.writeStringField('ErrorType', 'INVALID_STORE');

        gen.writeEndObject();
        string json_str = gen.getAsString();

        res.responseBody = Blob.valueOf(json_str);
        res.statusCode = 400;
      }
    } else {
      gen.writeStartObject();
      gen.writeStringField('ErrorDetails', 'Mandatory field(s) missing');
      gen.writeStringField('ErrorType', 'MANDATORY_FIELDS');
      gen.writeFieldName('ErrorFields');
      gen.writeStartArray();
      for (String s : mandatory) {
        gen.writeString(s);
      }
      gen.writeEndArray();

      gen.writeEndObject();
      string json_str = gen.getAsString();

      res.responseBody = Blob.valueOf(json_str);
      res.statusCode = 500;
    }

  }

  /*** FUTURE PRIVATE METHODS ***/
  @future
  private static void updateSapAutoNumberRecord(String sapAutoNumberName, Id contactId) {

    SapAutoNumber__c s = [SELECT Name, Contact__c FROM SapAutoNumber__c Where Name = :sapAutoNumberName LIMIT 1];
    s.Contact__c = contactId;
    update s;
  }

  //ESB Integration method
  @future(callout = true)
  public static void handleESBIntegration(String jsBody) {
    ESBLog__c thisLog = new ESBLog__c();
    thisLog.ESB_Configuration__c = [SELECT Id, Name FROM ESB_Configuration__c WHERE Name = 'Beanstore Save/Update Guest'].Id; //Get it from query
    thisLog.Request_Input__c = jsBody;
    JK_ESBManager ESB = new JK_ESBManager(thisLog);

    ESB.COMPILE();
    ESB.SEND();
    ESB.PARSE();
  }

  /*** PRIVATE METHODS ***/

  // PREPARE CONTACT BASED ON SAPID
  private static Contact handleContact(String title, String firstname, String lastname, String address, String zip, String city, String province,
                                       String prefix, String mobile, String nationality, String country, String email, String marketing, String profiling,
                     Date birthday, String gender, Date creationDt, String age, String openId, String unionId, String source, Id StoreId, 
                     Id SaleAssistantId, String SaleAssistantCode, String sapId, String CNCBDTFlag, String profilingcrossgroupFlag) {

    Contact handledContact;
    Country__c nation;

    if (nationality != null && nationality != '') { //Based on input parameter , find the appropiate Country lookup for Contact Nationality
      nation = [SELECT Id, Code__c FROM Country__c WHERE Code__c = :nationality LIMIT 1];
    }

    // CREATE NEW CONTACT
    if (sapId == null) {
      SAPAutoNumber__c sap = new SAPAutoNumber__c();
      insert sap;
      String newSapId = [SELECT Name FROM SAPAutoNumber__c WHERE Id = :sap.Id LIMIT 1].Name;

      handledContact = new Contact();
      handledContact.Salutation = title; // handleSalutationCode(title);
      handledContact.FirstName = firstname;
      handledContact.LastName = lastname;
      handledContact.MailingStreet = address;
      handledContact.MailingPostalCode = zip;
      handledContact.MailingCity = city;
      handledContact.MobilePhone = mobile;
      handledContact.Email = email;
      handledContact.MarketingConsent__c = consentBoolToPick(marketing);
      handledContact.ProfilingConsent__c = consentBoolToPick(profiling);
      handledContact.Birthdate = birthday;
      handledContact.Gender__c = gender;
      handledContact.AcquisitionDate__c = creationDt;
      handledContact.AgeRange__c = age;
      handledContact.OpenId__c = openId;
      handledContact.UnionId__c = unionId;
      handledContact.Source__c = 'WeChat';
      handledContact.WeChatSource__c = source;
      handledContact.SapId__c = newSapId;
      handledContact.FromWeChat__c = true;
      handledContact.WeChatUniqueId__c = unionId + mobile;
      handledContact.CustomerStatus__c = '0001';
      handledContact.NaturalPerson__c = 'X';
            handledContact.ProfilingCrossGroup__c = consentBoolToPick(profilingcrossgroupFlag);
            // 20220609
            handledContact.LastConsentUpdate__C=date.today();

      if (nation != null) {
        handledContact.Nationality__c = nation.Id;
      }

      if (country == 'CN' && countryWeChat.contains(province)) {
        handledContact.MailingCountry = countrySF[countryWeChat.indexOf(province)];
        handledContact.State__c = countrySF[countryWeChat.indexOf(province)];
      } else {
        handledContact.MailingCountry = country;
        handledContact.State__c = country;
      }
      handledContact.ResidenceRegion__c = LP_UpdateResidenceRegion.computeRegionFromCountry(country); //SFoA

      handledContact.MailingState = (country != null && !countryWeChat.contains(province)) ? province : null;

      // 2021-03-12: aggiornamento gestione mobile
      handledContact.MobilePhonePrefix__c = prefix;
      handledContact.WeChatPhonePrefix__c = prefix;
      handledContact.WeChatPhone__c = mobile;

      // 2021-04-21: aggiornamento gestione negozio registrazione
      handledContact.RegistrationStore__c = StoreId;
      handledContact.WeChatStore__c = StoreId;

      // 2021-07-01: aggiornamento introduzione SA registrazione WeChat
      handledContact.WeChatSaleAssistant__c = SaleAssistantId;
      handledContact.RegistrationSaleAssistant__c = SaleAssistantId;
      handledContact.WeChatSaleAssistantId__c = SaleAssistantCode;
            
            // 2021-10-12: aggiornamento RegistrationEvent__c Fujiwara
            if (source != null && source.toUppercase() == 'HFCAM') {
                handledContact.RegistrationEvent__c = '001';
                handledContact.LastEvent__c = '001';
      }
      
      // 2021-10-18: aggiornamento PIPLFlag
      handledContact.PIPLConsent__c = consentBoolToPick(CNCBDTFlag);

      // 2024-07-15: Use Sales Assistant ID to set as contact owner when it is not blank
      if (String.isNotBlank(SaleAssistantId)) {
        handledContact.OwnerId = SaleAssistantId;
      }

    } else { // PREPARE UPDATE EXISTING CONTACT

      handledContact = [SELECT Salutation, FirstName, LastName, MailingStreet, MailingPostalCode, MailingCity, MailingState, MobilePhone, Nationality__c, MailingCountry,
                        Email, MarketingConsent__c, ProfilingConsent__c, Birthdate, Gender__c, AcquisitionDate__c, AgeRange__c, Status__c, OpenId__c, UnionId__c,
                        Source__c, SapId__c, RegistrationStore__r.TaxiShopCode__c, FromWeChat__c, WeChatUniqueId__c, WeChatSource__c, MobilePhonePrefix__c, PIPLConsent__c, 
                        WeChatPhonePrefix__c, WeChatPhone__c, RegistrationStore__c, WeChatStore__c, WeChatStore__r.TaxiShopCode__c, WeChatSaleAssistant__c, RegistrationSaleAssistant__c, ProfilingCrossGroup__c
                        FROM Contact
                        WHERE SapId__c = :sapId
                        LIMIT 1];

      if (handledContact != null) {

        handledContact.Salutation = (title == null) ? handledContact.Salutation : title;
        handledContact.FirstName = (firstname == null) ? handledContact.FirstName : firstname;
        handledContact.LastName = (lastname == null) ? handledContact.LastName : lastname;

        if (nation != null) handledContact.Nationality__c = (nationality == null) ? handledContact.Nationality__c : nation.Id;        

        handledContact.MarketingConsent__c = (marketing == null) ? handledContact.MarketingConsent__c : consentBoolToPick(marketing);
        handledContact.ProfilingConsent__c = (profiling == null) ? handledContact.ProfilingConsent__c : consentBoolToPick(profiling);
                handledContact.ProfilingCrossGroup__c = (profilingcrossgroupFlag == null) ? handledContact.ProfilingCrossGroup__c : consentBoolToPick(profilingcrossgroupFlag);
        handledContact.Birthdate = (birthday == null) ? handledContact.Birthdate : birthday;
        handledContact.Gender__c = (gender == null) ? handledContact.Gender__c : gender;
        handledContact.AcquisitionDate__c = (creationDt == null) ? handledContact.AcquisitionDate__c : creationDt;
        handledContact.AgeRange__c = (String.isBlank(age)) ? handledContact.AgeRange__c : age;
        handledContact.OpenId__c = (String.isBlank(openId)) ? handledContact.OpenId__c : openId;
        handledContact.UnionId__c = (String.isBlank(unionId)) ? handledContact.UnionId__c : unionId;        
        handledContact.WeChatSource__c = (String.isNotBlank(handledContact.WeChatSource__c)) ? handledContact.WeChatSource__c : source;        
        handledContact.WeChatUniqueId__c = (String.isBlank(unionId) && String.isBlank(mobile)) ? handledContact.WeChatUniqueId__c : unionId + mobile;

        handledContact.FromWeChat__c = true;
        handledContact.Source__c = 'WeChat';

        // 2021-03-12: aggiornamento gestione mobile
        handledContact.MobilePhonePrefix__c = (String.isBlank(prefix)) ? handledContact.MobilePhonePrefix__c : prefix;
        handledContact.WeChatPhonePrefix__c = (String.isBlank(prefix)) ? handledContact.WeChatPhonePrefix__c : prefix;
        handledContact.WeChatPhone__c = (String.isBlank(mobile)) ? handledContact.WeChatPhone__c : mobile;
        handledContact.MobilePhone = (String.isBlank(mobile)) ? handledContact.MobilePhone : mobile;

        // 2021-04-21: aggiornamento gestione negozio registrazione
        if (handledContact.WeChatStore__c == null) handledContact.WeChatStore__c = StoreId;

        // 2021-04-21: aggiunta gestione dati tabelle satellite
        if (email != null) handledContact.Email = email;

        if (address != null) handledContact.MailingStreet = address;
        if (zip != null) handledContact.MailingPostalCode = zip;
        if (city != null) handledContact.MailingCity = city;

        if (country != null && province != null) { // handling of both
          if (country == 'CN' && countryWeChat.contains(province)) {
            handledContact.MailingCountry = countrySF[countryWeChat.indexOf(province)];
            handledContact.State__c = countrySF[countryWeChat.indexOf(province)];
            handledContact.MailingState = null;
          } else {
            handledContact.MailingCountry = country;
            handledContact.State__c = country;

            handledContact.MailingState = province;
          }
        } else if (country != null) { // handling of only country
          handledContact.MailingCountry = country;
          handledContact.State__c = country;
        }
        handledContact.ResidenceRegion__c = LP_UpdateResidenceRegion.computeRegionFromCountry(country); //SFoA

        // 2021-07-01: aggiornamento introduzione SA registrazione WeChat
        handledContact.WeChatSaleAssistant__c = SaleAssistantId;
        handledContact.WeChatSaleAssistantId__c = SaleAssistantCode;
                
                // 2021-10-12: aggiornamento RegistrationEvent__c Fujiwara
                if (source != null && source.toUppercase() == 'HFCAM') {
                    handledContact.RegistrationEvent__c = '001';
                    handledContact.LastEvent__c = '001';
        }
        
        // 2021-10-18: aggiornamento PIPLFlag
        handledContact.PIPLConsent__c = consentBoolToPick(CNCBDTFlag);
                // 20220609
                handledContact.LastConsentUpdate__C=date.today();
      }
    }

    return handledContact;
  }

  private static void handleContactInfo(Id contactId, String address, String zip, String city, String province,
                                        String prefix, String mobile, String nationality, String country, String email, String sapId, Boolean isPost) {

    Country__c ctr;
    Province__c prv;

    if (country != null && country != '') {
      ctr = [SELECT Id, Code__c FROM Country__c WHERE Code__c = :country LIMIT 1];
    }

    if (province != null && province != '' && country != null && country != '' && !countryWeChat.contains(province)) {
      prv = [SELECT Id, Code__c FROM Province__c WHERE Code__c = :province and CountryCode__c = :country LIMIT 1];
    }
    // CREATE NEW CONTACT RELATED OBJECTS ADDRESS/CONTACT_CHANNEL
    if (isPost == true) {

      if (address != null || zip != null || city != null || province != null || country != null) {
        insert createNewWeChatAddress(sapId, contactId, address, zip, city, province, country, true) ;
      }

      if (prefix != null || mobile != null) {

        insert createNewWeChatMobileContactChannel(sapId, contactId, prefix, mobile, true);
      }

      if (email != null) {
                
                insert createNewWeChatEmailContactChannel(sapId, contactId, email, true);
                
      }

    } else { //PREPARE ADDRESS/CONTACT_CHANNEL INFO

      if (address != null || zip != null || city != null || province != null || country != null) {
        List<Address__c> updAddress = [SELECT Id, Contact__c, Street__c, PostalCode__c, City__c, Province__c, Country__c, Source__c, FromWeChat__c, Locale__c, MainAddress__c
                                       FROM Address__c
                                       WHERE Contact__c = :contactId AND Type__c = '0' // added AND Type__c = '0' 
                                               order by fromWeChat__c desc, lastmodifieddate desc ]; // esiste sempre solo un indirizzo WeChat; la source non è affidabile (DWH)
                
                List<Address__c> BeanstoreAddress = [SELECT Id, Contact__c, Street__c, PostalCode__c, City__c, Province__c, Country__c, Source__c, FromWeChat__c, Locale__c
                                       FROM Address__c
                                       WHERE Contact__c = :contactId AND Type__c = '0' // added AND Type__c = '0' 
                                                and source__c='Beanstore' and MainAddress__c =  true order by  lastmodifieddate desc ];

                List<Address__c> AddToUpdate = new List<Address__c>();

        if (updAddress.size() > 0 && updAddress != null) { //Addresses associated with that contact exist in DB
                    
                    //At DB a WeChat address exists
                    if(updAddress[0].fromWeChat__c==true){
                         
                        if(BeanstoreAddress.size()>0 ){
                            
                            // If at DB Beanstore addresses exist --> Update existing WeChat Address as not Main.
                            AddToUpdate.add(UpdateWeChatAddress(updAddress[0], sapId, contactId, address, zip, city, province, country, false));
                        } else {
                            
                            // else it's main because it's the more recent
                            AddToUpdate.add(UpdateWeChatAddress(updAddress[0], sapId, contactId, address, zip, city, province, country, true));
                            
                            // devo abbassare eventuali altri MAIN a sistema
                            for(integer i=1; i < updAddress.size(); i++){
                                if(updAddress[i].MainAddress__c == true){
                                    updAddress[i].MainAddress__c = false;
                                    AddToUpdate.add(updAddress[i]);
                                }
                            }
                        }
              
                        update AddToUpdate;
                        
                    } else if (updAddress[0].fromWeChat__c==false && BeanstoreAddress.size()== 0 )  {
                        // Esistono Address a sistema, NON FromWeChat, associati al contact --> create Address FromWeChat main se non esiste un beanstore 
                        insert createNewWeChatAddress(sapId, contactId, address, zip, city, province, country, true) ;
                         // devo abbassare eventuali altri MAIN a sistema
                        for(integer i=1; i < updAddress.size(); i++){
                            if(updAddress[i].MainAddress__c == true){
                                updAddress[i].MainAddress__c = false;
                                AddToUpdate.add(updAddress[i]);
                            }
                        }
                        
                    } else if (updAddress[0].fromWeChat__c==false && BeanstoreAddress.size()>0 ){
                        // Esistono Address a sistema, NON FromWeChat, associati al contact --> create Address FromWeChat NOT main se esiste un beanstore
                        insert createNewWeChatAddress(sapId, contactId, address, zip, city, province, country, false) ;
                    }
                    
        } else { 
                    // non ci sono Address a sistema associati al contact --> create Address FromWeChat MAIN
                    insert createNewWeChatAddress(sapId, contactId, address, zip, city, province, country, true) ;
        }

      }

      if (prefix != null || mobile != null) {

        List<ContactChannel__c> updChannelPhone = [SELECT Id, Contact__c, PhonePrefix__c, Phone__c, Type__c, Source__c, FromWeChat__c
                                                   FROM ContactChannel__c
                                                   WHERE Contact__c = :contactId AND  Type__c = 'MOB_PHONE' 
                                                           order by fromWeChat__c desc, lastmodifieddate desc LIMIT 1]; 
                List<ContactChannel__c> BeanstoreChannelPhone = [SELECT Id, Contact__c, PhonePrefix__c, Phone__c, Type__c, Source__c, FromWeChat__c
                                                   FROM ContactChannel__c
                                                   WHERE Contact__c = :contactId AND  Type__c = 'MOB_PHONE' and source__C='Beanstore'  and MainChannel__c =  true
                                                           order by  lastmodifieddate desc]; 
                List<ContactChannel__C> CCToUpdate = new List<ContactChannel__c>();

        if (updChannelPhone.size() > 0 && updChannelPhone != null) { //CC associated with that contact exist in DB
                    
                    //At DB a WeChat address exists
                    if(updChannelPhone[0].fromWeChat__c==true){
                        if(BeanstoreChannelPhone.size()>0){
                            // If at DB Beanstore CC exist --> Update existing WeChat CC as not Main.
                            CCToUpdate.add(updateWeChatMobileContactChannel( updChannelPhone[0],sapId, contactId, prefix, mobile, false));
                        } else {
                            
                            // else it's main because it's the more recent
                            CCToUpdate.add(updateWeChatMobileContactChannel( updChannelPhone[0],sapId, contactId, prefix, mobile, true));
                            
                            // devo abbassare eventuali altri MAIN a sistema
                            for(integer i=1; i < updChannelPhone.size(); i++){
                                if(updChannelPhone[i].MainChannel__c == true){
                                    updChannelPhone[i].MainChannel__c = false;
                                    CCToUpdate.add(updChannelPhone[i]);
                                }
                            }
                        }
                        
                        update CCToUpdate;
                        
                    } else if (updChannelPhone[0].fromWeChat__c==false && BeanstoreChannelPhone.size()==0){
                        
                        // Esistono CC a sistema, NON FromWeChat, associati al contact --> create CC FromWeChat main se non esiste un beanstore
                        insert createNewWeChatMobileContactChannel(sapId, contactId, prefix, mobile, true);
                        for(integer i=1; i < updChannelPhone.size(); i++){
                                if(updChannelPhone[i].MainChannel__c == true){
                                    updChannelPhone[i].MainChannel__c = false;
                                    CCToUpdate.add(updChannelPhone[i]);
                                }
                         }
                        
                    } else if (updChannelPhone[0].fromWeChat__c==false && BeanstoreChannelPhone.size()>0){
                        
                        // Esistono CC a sistema, NON FromWeChat, associati al contact --> create CC FromWeChat NOT main se non esiste un beanstore
                        insert createNewWeChatMobileContactChannel(sapId, contactId, prefix, mobile, false);
                        
                    }
                    
        } else { 
                    
                    // non ci sono CC a sistema associati al contact --> create CC FromWeChat MAIN
                    insert createNewWeChatMobileContactChannel(sapId, contactId, prefix, mobile, true);

        }
      }

      if (email != null) { //Update existing email channel
                
                List<ContactChannel__c> updChannelMail = [SELECT Id, Contact__c, PhonePrefix__c, Phone__c, Type__c, Source__c, FromWeChat__c
                                                   FROM ContactChannel__c
                                                   WHERE Contact__c = :contactId AND  Type__c = 'EMAIL' 
                                                           order by fromWeChat__c desc, lastmodifieddate desc LIMIT 1]; 
                List<ContactChannel__c> BeanstoreChannelMail = [SELECT Id, Contact__c, PhonePrefix__c, Phone__c, Type__c, Source__c, FromWeChat__c
                                                   FROM ContactChannel__c
                                                   WHERE Contact__c = :contactId AND  Type__c = 'EMAIL' and source__C='Beanstore'  and MainChannel__c =  true
                                                           order by  lastmodifieddate desc]; 
                List<ContactChannel__C> CCToUpdate = new List<ContactChannel__c>();

        if (updChannelMail.size() > 0 && updChannelMail != null) { //CC associated with that contact exist in DB
                    
                    //At DB a WeChat address exists
                    if(updChannelMail[0].fromWeChat__c==true){
                        if(BeanstoreChannelMail.size()>0){
                            // If at DB Beanstore CC exist --> Update existing WeChat CC as not Main.
                            CCToUpdate.add(updateWeChatEmailContactChannel( updChannelMail[0],sapId, contactId, email, false));
                        } else {
                            
                            // else it's main because it's the more recent
                            CCToUpdate.add(updateWeChatEmailContactChannel( updChannelMail[0],sapId, contactId, email, true));
                            
                            // devo abbassare eventuali altri MAIN a sistema
                            for(integer i=1; i < updChannelMail.size(); i++){
                                if(updChannelMail[i].MainChannel__c == true){
                                    updChannelMail[i].MainChannel__c = false;
                                    CCToUpdate.add(updChannelMail[i]);
                                }
                            }
                        }
                        
                        update CCToUpdate;

        } else if (updChannelMail[0].fromWeChat__c==false && BeanstoreChannelMail.size()==0){
                        
                        // Esistono CC a sistema, NON FromWeChat, associati al contact --> create CC FromWeChat main se non esiste un beanstore
                        insert createNewWeChatEmailContactChannel(sapId, contactId, email, true);
                        // devo abbassare eventuali altri MAIN a sistema 
                        for(integer i=1; i < updChannelMail.size(); i++){
                                if(updChannelMail[i].MainChannel__c == true){
                                    updChannelMail[i].MainChannel__c = false;
                                    CCToUpdate.add(updChannelMail[i]);
                                }
                         }
                        
                    } else if (updChannelMail[0].fromWeChat__c==false && BeanstoreChannelMail.size()>0){
                        
                        // Esistono CC a sistema, NON FromWeChat, associati al contact --> create CC FromWeChat NOT main se non esiste un beanstore
                        insert createNewWeChatEmailContactChannel(sapId, contactId, email, false);
                        
                    }
                    
        } else { 
                    
                    // non ci sono CC a sistema associati al contact --> create CC FromWeChat MAIN
                    insert createNewWeChatEmailContactChannel(sapId, contactId, email, true);

        }
      }

    }

  }
    
    // Create new Address
  private static Address__c createNewWeChatAddress(String sapId, Id contactId, String address, String zip, String city, String province, String country, boolean IsMain) {

        Country__c ctr;
    Province__c prv;

    if (country != null && country != '') {
      ctr = [SELECT Id, Code__c FROM Country__c WHERE Code__c = :country LIMIT 1];
    }

    if (province != null && province != '' && country != null && country != '' && !countryWeChat.contains(province)) {
      prv = [SELECT Id, Code__c FROM Province__c WHERE Code__c = :province and CountryCode__c = :country LIMIT 1];
    }
        
    Address__c adr = new Address__c();
    adr.Contact__c = contactId;
    adr.Street__c = address;
    adr.PostalCode__c = zip;
    adr.City__c = city;

    adr.Province__c = (country != null && prv != null && !countryWeChat.contains(province)) ? prv.Id : null;

    if (country == 'CN' && countryWeChat.contains(province)) {
      adr.Country__c = [SELECT Id, Code__c FROM Country__c WHERE Code__c = :countrySF[countryWeChat.indexOf(province)] LIMIT 1].Id;
    } else if (country != null && ctr != null) {
      adr.Country__c = ctr.Id;
    }

    adr.Source__c = 'WeChat';
        adr.Locale__c = '-';
        adr.MainAddress__c = IsMain;
        adr.Type__c = '0';
    adr.OtherType__c = '03';
    //adr.AddressKey__c = sapId + '|0|03|-|WeChat';
    
    adr.FromWeChat__c = true;

    return adr;
  }
    
    // Update existing WeChat addresses
  @testVisible
  private static Address__c UpdateWeChatAddress(address__c a, String sapId, Id contactId, String address, String zip, String city, String province, String country, boolean IsMain) {
        Country__c ctr;
    Province__c prv;

    if (country != null && country != '') {
      ctr = [SELECT Id, Code__c FROM Country__c WHERE Code__c = :country LIMIT 1];
    }

    if (province != null && province != '' && country != null && country != '' && !countryWeChat.contains(province)) {
      prv = [SELECT Id, Code__c FROM Province__c WHERE Code__c = :province and CountryCode__c = :country LIMIT 1];
    }
        
        a.Street__c = address;
    a.PostalCode__c = zip;
    a.City__c = city;
    a.Province__c = (prv != null) ? prv.Id : null;
    a.FromWeChat__c = true;
        if(IsMain==true){
            a.MainAddress__c = (a.Locale__c =='-') ? true : false;
        } else {
            a.MainAddress__c = IsMain;
        }

    if (country != null && country != '' && ctr != null) {

      if (country == 'CN' && countryWeChat.contains(province)) {
        a.Country__c = [SELECT Id, Code__c FROM Country__c WHERE Code__c = :countrySF[countryWeChat.indexOf(province)] LIMIT 1].Id;
      } else if (country != null && ctr != null) {
        a.Country__c = ctr.Id;
      }
    } else {
      a.Country__c = null;
    }

    return a;
  }
    
    // Create new Mobile Contact Channel from WeChat
  private static ContactChannel__c createNewWeChatMobileContactChannel(String sapId, Id contactId, String prefix, String mobile, boolean IsMain) {

        ContactChannel__c channelPhoneToInsert = new ContactChannel__c();
    channelPhoneToInsert.Contact__c = contactId;
    channelPhoneToInsert.PhonePrefix__c = prefix;
    channelPhoneToInsert.Phone__c = mobile;
    channelPhoneToInsert.Type__c = 'MOB_PHONE';
    channelPhoneToInsert.Source__c = 'WeChat';
    channelPhoneToInsert.MainChannel__c = IsMain;
        //channelPhoneToInsert.ChannelKey__c = sapId + '|MOB_PHONE|WeChat';
    channelPhoneToInsert.FromWeChat__c = true;

    return channelPhoneToInsert;
  }
    
    // Update WeChat Mobile Contact Channel 
  private static ContactChannel__c updateWeChatMobileContactChannel(ContactChannel__c cc, String sapId, Id contactId, String prefix, String mobile, boolean IsMain) {

        cc.PhonePrefix__c = prefix;
    cc.Phone__c = mobile;
    cc.FromWeChat__c = true;
        cc.MainChannel__c= IsMain;

    return cc;
  }
    
    // Create new Email Contact Channel from WeChat
  private static ContactChannel__c createNewWeChatEmailContactChannel(String sapId, Id contactId, String email, boolean IsMain) {
        
        ContactChannel__c channelMailToInsert = new ContactChannel__c();
    channelMailToInsert.Contact__c = contactId;
    channelMailToInsert.Email__c = email;
    channelMailToInsert.Type__c = 'EMAIL';
    channelMailToInsert.Source__c = 'WeChat';
    channelMailToInsert.MainChannel__c = IsMain; 
        //channelMailToInsert.ChannelKey__c = sapId + '|EMAIL|WeChat';
    channelMailToInsert.FromWeChat__c = true;

    return channelMailToInsert;
  }
    
    // Update WeChat Email Contact Channel 
  private static ContactChannel__c updateWeChatEmailContactChannel(ContactChannel__c cc, String sapId, Id contactId, String email, boolean IsMain) {

        cc.Email__c = email;
    cc.FromWeChat__c = true;
        cc.MainChannel__c= IsMain;

    return cc;
  }

  public static String consentBoolToPick(String input) {
    if (input != null) {
      input = input.toLowerCase();
    }
    String output;

    switch on input {
      when 'true', '1', 'y', 'yes' {
        output = 'Y';
      }
      when 'false', '0', 'n', 'no' {
        output = 'N';
      }
      when else {
        output = '.';
      }
    }

    return output;
  }

  public static String consentPickToBool(String input) {
    if (input != null) {
      input = input.toLowerCase();
    }
    String output;

    switch on input {
      when 'y', 'true', 'yes' {
        output = 'true';
      }
      when 'n', 'false', 'no' {
        output = 'false';
      }
      when '.', '-' {
        output = null;
      }
      when else {
        output = null;
      }
    }

    return output;
  }

  // Handle ESB country/province input based on parameters provided
  private static Map<String, String> handleESBCountryProvince(String country, String province) {

    Map<String, String> outputMap = new Map<String, String> ();
    if (country == 'CN' && countryWeChat.contains(province)) {
      outputMap.put('Country', countrySF[countryWeChat.indexOf(province)]);
      outputMap.put('Province', '');

    } else if (country != null) {
      outputMap.put('Country', country);
      outputMap.put('Province', province);
    }

    return outputMap;
  }

  private static String handleSalutationCode(String title) {

    Map<String, String> picklistValues = new Map<String, String> ();
    Schema.DescribeFieldResult fieldResult = Contact.Salutation.getDescribe();

    for (Schema.PicklistEntry l : fieldResult.getPicklistValues()) {
      picklistValues.put(l.getLabel().toUpperCase(), l.getValue());
    }

    if (picklistValues.keySet().contains(title)) {
      return picklistValues.get(title);
    } else {
      return null;
    }
  }

  private static String handleSalutationValue(String title) {

    Map<String, String> picklistValues = new Map<String, String> ();
    Schema.DescribeFieldResult fieldResult = Contact.Salutation.getDescribe();

    for (Schema.PicklistEntry l : fieldResult.getPicklistValues()) {
      picklistValues.put(l.getValue(), l.getLabel().toUpperCase());
    }

    if (picklistValues.keySet().contains(title)) {
      return picklistValues.get(title);
    } else {
      return null;
    }
  }

  private static String handleHybrisTitle(String Title) {
    String titleHybris = '';
    switch on(Title.toLowerCase()) {
      when 'mr', '0002' {
        titleHybris = 'mr';
      }
      when 'ms', 'z000' {
        titleHybris = 'miss';
      }
      when 'mrs', '0001' {
        titleHybris = 'mrs';
      }
      when else {
        titleHybris = '';
      }
    }
    return titleHybris;
  }

  // PREPARE STORE CODE LIST
  private static Map<String, Id> prepareStoreMap() {
    List<Account> tmpList = [SELECT Id, TaxiShopCode__c FROM Account WHERE TaxiShopCode__c != null];
    Map<String, Id> response = new Map<String, Id> ();
    for (Account a : tmpList) {
      response.put(a.TaxiShopCode__c, a.Id);
    }
    return response;
  }

  // PREPARE SALE ASSOCIATE LIST
  private static Map<String, Id> preparesaleAssistantMap() {
    List<User> tmpList = [SELECT Id, PersonId__c FROM User WHERE PersonId__c != null];
    Map<String, Id> response = new Map<String, Id> ();
    for (User u : tmpList) {
      response.put(u.PersonId__c, u.Id);
    }
    return response;
  }

}